#include "Socket.h"


in_addr_t inet_addr_ex(const char* host)
{
	struct in_addr result;
	result.s_addr = inet_addr(host);
	if (result.s_addr == INADDR_NONE) {
		struct hostent* ht = 0;
		if ((ht = gethostbyname(host)) != 0) {
			result = *((struct in_addr*)ht->h_addr);
		}
	}
#ifdef _MSC_VER
	return result.s_addr;
#elif __GNUC__
	return result.s_addr;
#endif
}

int Socket_SetNonblock(SOCKET fd, long act) {
	unsigned long arg = (act ? 1 : 0);
	return ioctlsocket(fd, FIONBIO, &arg);
}

int Socket_SetNoDelay(SOCKET fd, long act) {
#ifndef TCP_NODELAY
	#define TCP_NODELAY 0x0001
#endif
	long bNoDelay = act;
	return (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
					 (char *) &bNoDelay, sizeof(bNoDelay)));
}

int Socket_SetLinger(SOCKET fd, u_short l_onoff, u_short l_linger)
{
	struct linger lin = {l_onoff, l_linger};
	return setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&lin, sizeof(lin));
}

int Socket_SetKeepAlive(SOCKET fd, long act) 
{
	unsigned long arg = (act ? 1 : 0);
	return (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
					 (char *) &arg, sizeof(arg)));
}


/**
 * recv within timeout
 * @param fd : socket
 * @param buffer : data
 * @param size : data size
 * @param sec : second
 * @return -1 : socket error
 *		    0 : recv close
 *			-2 : timeout
 *			size: success
 */
int Socket_RecvTimeout(SOCKET fd, void* buffer, int size, int sec)
{
	struct timeval timeout;
	fd_set readset, rset;
	int ret;
	char* buf = (char*)buffer;
	int datasize=0;
	int datacount = size;
	int lefttime = 0;

	FD_ZERO(&readset);
	FD_SET(fd, &readset);

	while(datasize != datacount){
		rset = readset;
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;
		lefttime++;

		ret = select(fd+1, &rset, NULL, NULL, &timeout);
		if (-1 == ret) {//error
#ifdef __GNUC__
			if (EINTR == socket_errno)
				continue;
#endif
			return -1;
		}else if (0 == ret) {//timeout
		}else {
			if (FD_ISSET(fd, &rset)){
				//peek
				ret = recv(fd, buf+datasize, datacount - datasize, 0);
				if (ret <= 0) {
					return ret;
				}else {//ret > 0
					lefttime = 0;
					datasize += ret;
				}
			}
		}

		if (datasize != datacount) {
			if (lefttime >= sec){
				//timeout
				return -2;
			}
		}
	}

	return datasize;
}

/**
 * recv once
 *@return -1 : socket error
 *        0 : recv close
 *	 	 -2 : timeout
 *		  >0: success
 */
int Socket_RecvOnceTimeout(SOCKET fd, void* buffer, int size, int sec)
{
	struct timeval timeout;
	fd_set readset;
	int ret;
	char* buf = (char*)buffer;

	FD_ZERO(&readset);
	FD_SET(fd, &readset);
	timeout.tv_sec = sec;
	timeout.tv_usec = 0;

	ret = select(fd+1, &readset, NULL, NULL, &timeout);
	if (-1 == ret) {//error
		return -1;
	}
	else if (0 == ret) {//timeout
		return -2;
	}
	else {
		if (FD_ISSET(fd, &readset)){
			return recv(fd, buf, size, 0);
		}
		return -1;
	}

}
